/*
* @Author: Administrator
* @Date:   2021-08-19 21:50:21
* @Last Modified by:   Administrator
* @Last Modified time: 2021-08-30 22:42:33
*/

//////////
//词法解析器 //
//////////



/*
 *词法分析(数据结构叫Token)
 *生成数据结构,例:LET(0,'let',0)
 */
class Token{
	/**
	 * @param  {[type]} type       [单词分类编号]
	 * @param  {[type]} literal    [单词分类字符串变量值]
	 * @param  {[type]} lineNumber [单词所在行号]
	 */
	constructor(type,literal,lineNumber){
		this.TokenType=type;
		this.literal=literal;
		this.lineNumber=lineNumber;
	}

	getType(){
		return this.TokenType;
	}

	getLiteral(){
		return this.literal;
	}

	getLineNumber(){
		return this.lineNumber;
	}

}

class Lexer{
	/**
	 * 构造函数
	 * @param  {[sourceCode]} sourceCode       [文本框中输入的文本]
	 */
	constructor(sourceCode){
		//数据初始化
		this.initTokenType();
		this.initKeywords();
		this.sourceCode=sourceCode;
		this.poistion=0;
		this.readPosition=0;//读到第几个字符了
		this.lineCount=0;//行号(读到到第几行了)
		this.ch='';//当前读到的字符

		this.observer = null
		this.observerContext = null

	}

	//单词初始化
	initTokenType(){
		this.ILLEGAL=-2;//非法字符串组和
		this.EOF=-1;//文本末尾终结符
		this.LET=0;//定义变量关键字
		this.IDENTIFIER=1;//变量标识符
	    this.ASSIGN_SIGN = 2//等号
		this.PLUS_SIGN=3;//+加号
		this.INTEGER=4;//数字
		this.SEMICOLON=5;//;分号

		this.IF=6;
		this.ELSE=7;

		//change here
		this.MINUS_SIGN = 8; //-减号
		this.BANG_SIGN = 9;//！感叹号
		this.ASTERISK = 10;//*乘号
		this.SLASH = 11;//'/'除号
		this.LT = 12;//<箭括号
		this.GT = 13;//>箭括号
		this.COMMA = 14

		this.FUNCTION = 15
		this.TRUE = 16
		this.FALSE = 17
		this.RETURN = 18

		this.LEFT_BRACE = 19//左大括号
		this.RIGHT_BRACE = 20//右大括号
		this.EQ = 21
		this.NOT_EQ = 22
		this.LEFT_PARENT = 23;//左小括号
		this.RIGHT_PARENT = 24;//右小括号

	}

	//嘻哈表，关键字
	initKeywords(){
		this.keyWordMap=[];
		this.keyWordMap['let']=new Token(this.LET,"let",0);
		this.keyWordMap['if']=new Token(this.IF,"if",0);
		this.keyWordMap['else']=new Token(this.ELSE,"else",0);

		//change here
		this.keyWordMap["fn"] = new Token(this.FUNCTION, "fn", 0)
		this.keyWordMap["true"] = new Token(this.TRUE, "true", 0)
		this.keyWordMap["false"] = new Token(this.FALSE, "false", 0)
		this.keyWordMap["return"] = new Token(this.RETURN, "return", 0)
	}

	setLexingOberver(o,context){
		if(o!==null && o!==undefined){
			this.observer=o;
			this.observerContext=context;
		}
	}

	getKeyWords(){
		return this.keyWordMap;
	}

	//从输入的字符串中读取字符，每次从字符串中读取1个字符
	readChar(str){
		if(this.readPosition>=this.sourceCode.length){
			//读取字符串结束
			this.ch=-1;
		}else{
			this.ch=this.sourceCode[this.readPosition];
		}
		this.poistion=this.readPosition;
		this.readPosition++;

	}

	//change here
	peekChar () {
		if (this.readPosition >= this.sourceCode.length) {
			return 0
		} else {
			return this.sourceCode[this.readPosition]
		}
	}

	//获取行号和新的一行的第一个字符
	skipWhiteSpaceAndNewLine(){
		while(this.ch===' ' || this.ch==='\t' || this.ch==='\n'){
			if(this.ch==='\t' || this.ch==='\n'){
				this.lineCount++;
			}
			//读取下一个字符
			this.readChar('skipWhiteSpaceAndNewLine');
		}
	}

	//生成数据结构,
	
	/**
	 * 生成数据结构
	 * 例:
	 *    let x=y+5;    
	 *    LET(0,'let',0) IDENTIFIER(1,'x',0) EQUAL_SIGN(2,'=',0) IDENTIFIER(1,"y",0) PLUS_SIGN(3,"+",0) NUMBER(4,"5",0) SEMICOLON(5,";",0)
	 */
	nextToken(){
		var tok;
		//忽略掉所有空格和换行，回车
		this.skipWhiteSpaceAndNewLine();
		var lineCount=this.lineCount;
		switch(this.ch){
			case '=':
				if (this.peekChar() === '=') {
					tok = new Token(this.EQ, "==", lineCount);
				} else {
					tok = new Token(this.ASSIGN_SIGN, "=", lineCount);
				}
				break
			case ';':
				tok = new Token(this.SEMICOLON, ";", lineCount);
				break;
			case '+':
				tok = new Token(this.PLUS_SIGN, "+", lineCount);
				break;
			case -1:
				tok = new Token(this.EOF, "", lineCount);
				break;
			//change here
			case '-':
				tok = new Token(this.MINUS_SIGN, "-", lineCount);
				break;
			case '!':
				if (this.peekChar() === '=') {
					this.readChar();
					tok = new Token(this.NOT_EQ, "!=", lineCount);
				} else {
					tok = new Token(this.BANG_SIGN, "!", lineCount);
				}
				break;
			case '*':
				tok = new Token(this.ASTERISK, "*", lineCount);
				break;
			case '/':
				tok = new Token(this.SLASH, "/", lineCount);
				break;
			case '<':
				tok = new Token(this.LT, "<", lineCount);
				break;
			case '>':
				tok = new Token(this.GT, ">", lineCount);
				break;
			case ',':
				tok = new Token(this.COMMA, ",", lineCount);
				break;
			case '{':
				tok = new Token(this.LEFT_BRACE, "{", lineCount);
				break;
			case '}':
				tok = new Token(this.RIGHT_BRACE, "}", lineCount);
				break;
			case '(':
				tok = new Token(this.LEFT_PARENT, "(", lineCount);
				break;
			case ')':
				tok = new Token(this.RIGHT_BRACE, ")", lineCount);
				break;
			default:
				/**
				 * 字母和数字走这里
				 */
				//判断读到的内容是不是字母组成的字符串
				var res=this.readIdentifier();
				if(res!==false){
					if(this.keyWordMap[res]!==undefined){
						tok=this.keyWordMap[res];
					}else{
						tok=new Token(this.IDENTIFIER,res,lineCount);
					}
				}else{
					//判断读到的内容是不是数字
					res=this.readNumber();
					if(res!==false){
						tok=new Token(this.INTEGER,res,lineCount);
					}
				}

				if(res===false){
					tok=undefined;
				}
		}

		this.readChar('nextToken');
		return tok;
	}

	notifyObserver(token){
		if (this.observer !== null) {
			this.observer.notifyTokenCreation(token, 
			this.observerContext, this.position - 1, 
			this.readPosition)
		}
		
	}

	//用来辨认读取到的字符是不是26个字符
	isLetter(ch){
		return ('a'<=ch && ch<='z') ||
			   ('A'<=ch && ch<='Z') ||
			   (ch==='_');
	}

	//当读到的内容是不是全部使用字母组成的字符串
	readIdentifier(){
		var identifier='';
		//循环判断是不是字母和下划线（空格不是就停止循环判断）
		/*while(this.isLetter(this.ch)){
			identifier+=this.ch;
			this.readChar('readIdentifier');
		}*/

		for(;;){
			if(this.isLetter(this.ch)){
				identifier+=this.ch;
				this.readChar('readIdentifier');
			}else{
				this.readPositionRestore();
				break;
			}
		}

		if(identifier.length>0){
			return identifier;
		}

		return false;
	}

	//判断字符中是不是0到9之间
	isDigit(ch){
		return '0'<=ch && ch<='9';
	}

	//读取数字字符串
	readNumber(){
		var number='';
		//循环判断是不是数字（空格不是就停止循环判断）
		/*while(this.isDigit(this.ch)){
			number+=this.ch;
			this.readChar('readNumber');
		}*/

		for(;;){
			if(this.isDigit(this.ch)){
				number+=this.ch;
				this.readChar('readIdentifier');
			}else{
				this.readPositionRestore();
				break;
			}
		}

		if(number.length>0){
			return number;
		}

		return false;
	}

	//遇到特殊字符不读取,readPosition复原上一次的值
	readPositionRestore(){
		switch(this.ch){
			case '=':
				this.readPosition--;
				this.ch=this.sourceCode[this.readPosition];
				break
			case ';':
				this.readPosition--;
				this.ch=this.sourceCode[this.readPosition];
				break;
			case '+':
				this.readPosition--;
				this.ch=this.sourceCode[this.readPosition];
				break;
			case '-':
				this.readPosition--;
				this.ch=this.sourceCode[this.readPosition];
				break;
			case '!':
				this.readPosition--;
				this.ch=this.sourceCode[this.readPosition];
				break;
			case '*':
				this.readPosition--;
				this.ch=this.sourceCode[this.readPosition];
				break;
			case '/':
				this.readPosition--;
				this.ch=this.sourceCode[this.readPosition];
				break;
			case '<':
				this.readPosition--;
				this.ch=this.sourceCode[this.readPosition];
				break;
			case '>':
				this.readPosition--;
				this.ch=this.sourceCode[this.readPosition];
				break;
			case ',':
				this.readPosition--;
				this.ch=this.sourceCode[this.readPosition];
				break;
			case '{':
				this.readPosition--;
				this.ch=this.sourceCode[this.readPosition];
				break;
			case '}':
				this.readPosition--;
				this.ch=this.sourceCode[this.readPosition];
				break;
			case '(':
				this.readPosition--;
				this.ch=this.sourceCode[this.readPosition];
				break;
			case ')':
				this.readPosition--;
				this.ch=this.sourceCode[this.readPosition];
				break;
		}
	}


	//执行词法分析
	lexing(){
		//第一步读取字符串第一个字符
		//从输入的字符串中读取字符，每次从字符串中读取1个字符
		this.readChar('lexing')
		// change here
		this.tokens = []
		var token = this.nextToken()
		while(token !== undefined && token.getType() !== this.EOF) {
			this.tokens.push(token);
			token = this.nextToken();
		}

		this.tokens.push(token);
		console.log("============= start Lexer =============");
		console.log(" ")
		console.log(this.tokens);
		console.log(" ")
		console.log("============= end Lexer =============");
		console.log(" ")
		console.log(" ")
	}


}

// export default Lexer;

// module.exports=Lexer;
